/**
 * 服务器启动入口文件
 * 核心职责：
 *   - 协调数据库连接与服务器启动流程
 *   - 管理服务器生命周期（启动、运行、关闭）
 *   - 处理启动过程中的错误与异常
 *   - 提供清晰的运行状态反馈
 *
 * 设计理念：
 *   - 先确保数据库连接正常，再启动HTTP服务
 *   - 提供完整的错误处理机制
 *   - 支持优雅关闭，保护数据完整性
 *   - 环境感知的启动配置
 */

// ======================== 模块导入 ========================
// 导入配置好的Express应用实例（包含中间件、路由等所有配置）
const app = require('./app');
// 导入Sequelize数据库连接实例（已配置好的数据库连接）
const sequelize = require('./config/db');

// ======================== 配置参数 ========================
/**
 * 服务器端口配置
 * 优先级：环境变量 > 默认值(8888)
 * 环境变量从.env文件加载（通过dotenv在app.js中配置）
 */
const PORT = process.env.PORT || 8888;

// 从环境变量中获取数据库同步开关配置
const DB_SYNC = process.env.DB_SYNC === 'true';

// 记录服务器实例，用于后续关闭操作
let server;

// ======================== 数据库与服务器启动流程 ========================
/**
 * 启动流程说明：
 * 1. 根据DB_SYNC环境变量决定是否同步数据库模型与表结构
 * 2. 数据库操作成功后（同步或仅连接验证），启动HTTP服务器
 * 3. 任何环节失败都将捕获并处理错误
 */
const startServer = () => {
  // 启动HTTP服务器并监听指定端口
  server = app.listen(PORT, () => {
    // 服务器启动成功提示
    console.log(`🚀 服务器启动成功`);
    console.log(`🔗 访问地址: http://localhost:${PORT}`);
    console.log(`📅 启动时间: ${new Date().toISOString()}`);
  });
};

// 根据DB_SYNC环境变量决定执行同步数据库还是仅验证连接
if (DB_SYNC) {
  // 执行数据库同步并启动服务器
  sequelize
    // 同步Sequelize模型到数据库
    .sync({
      // alter: true 表示：
      // - 若表不存在则创建
      // - 若表已存在，仅修改结构差异（不删除数据）
      // - 适合开发环境，生产环境建议使用迁移(migrations)
      alter: process.env.NODE_ENV !== 'production',
    })
    .then(() => {
      // 数据库同步成功
      console.log(`✅ 数据库同步完成 [环境: ${process.env.NODE_ENV || 'development'}]`);
      console.log(`📦 数据库连接: ${sequelize.config.database}@${sequelize.config.host}`);
      // 启动服务器
      startServer();
    })
    .catch((err) => {
      // 数据库同步失败处理
      console.error('❌ 数据库同步失败:', err.name);
      console.error('📝 错误详情:', err.message);

      // 开发环境显示完整错误堆栈，生产环境简化
      if (process.env.NODE_ENV === 'development') {
        console.error('🔍 错误堆栈:', err.stack);
      }

      // 数据库连接失败时，无需继续启动服务器
      process.exit(1); // 非0状态码表示异常退出
    });
} else {
  // 仅验证数据库连接是否成功,不执行同步
  sequelize
    // 验证数据库连接
    .authenticate()
    .then(() => {
      // 数据库连接成功
      console.log(`✅ 数据库连接完成 [环境: ${process.env.NODE_ENV || 'development'}]`);
      console.log(`📦 数据库连接: ${sequelize.config.database}@${sequelize.config.host}`);
      // 启动服务器
      startServer();
    })
    .catch((err) => {
      // 数据库同步失败处理
      console.error('❌ 数据库同步失败:', err.name);
      console.error('📝 错误详情:', err.message);

      // 开发环境显示完整错误堆栈，生产环境简化
      if (process.env.NODE_ENV === 'development') {
        console.error('🔍 错误堆栈:', err.stack);
      }

      // 数据库连接失败时，无需继续启动服务器
      process.exit(1); // 非0状态码表示异常退出
    });
}

// ======================== 服务器优雅关闭机制 ========================
/**
 * 处理进程终止信号
 * 支持的信号：
 * - SIGINT: 用户按下Ctrl+C时触发
 * - SIGTERM: 系统请求终止进程时触发（如Docker停止容器）
 *
 * 优雅关闭流程：
 * 1. 停止接收新请求
 * 2. 等待当前处理中的请求完成
 * 3. 关闭数据库连接
 * 4. 退出进程
 */
const gracefulShutdown = async (signal) => {
  console.log(`\n📢 收到关闭信号: ${signal}`);
  console.log(`⏳ 正在优雅关闭服务器...`);

  try {
    // 1. 关闭HTTP服务器，停止接收新请求
    if (server) {
      await new Promise((resolve) => server.close(resolve));
      console.log('✅ HTTP服务器已关闭');
    }

    // 2. 关闭数据库连接
    await sequelize.close();
    console.log('✅ 数据库连接已关闭');

    console.log('👋 所有资源已释放，服务器成功关闭');
    process.exit(0); // 正常退出
  } catch (err) {
    console.error('❌ 关闭过程中发生错误:', err.message);
    process.exit(1); // 异常退出
  }
};

// 注册信号处理器
process.on('SIGINT', gracefulShutdown);
process.on('SIGTERM', gracefulShutdown);

// ======================== 未捕获异常处理 ========================
/**
 * 捕获未处理的同步异常
 * 防止服务器因未捕获的错误而意外崩溃
 */
process.on('uncaughtException', (err) => {
  console.error('❌ 未捕获的同步异常:', err.name);
  console.error('📝 错误详情:', err.message);

  if (process.env.NODE_ENV === 'development') {
    console.error('🔍 错误堆栈:', err.stack);
  }

  // 发生严重错误时，尝试优雅关闭后退出
  gracefulShutdown('uncaughtException').catch(() => process.exit(1));
});

/**
 * 捕获未处理的Promise拒绝
 * 处理异步操作中未被.catch()捕获的错误
 */
process.on('unhandledRejection', (reason, promise) => {
  console.error('❌ 未处理的Promise拒绝:');
  console.error('📝 原因:', reason);
  console.error('🔗 关联Promise:', promise);

  // 对于严重的异步错误，同样触发优雅关闭
  gracefulShutdown('unhandledRejection').catch(() => process.exit(1));
});
